import { Pool } from "../../../base/pool/Pool";
import { Handler } from "../../../base/utils/Handler";
import { HttpRequest } from "./HttpRequest";


/**
 * Http节点，实现接口简化，request复用池
 */
export class HttpNode {
    private _pool:Pool<HttpRequest> = new Pool<HttpRequest>(HttpRequest);

    /**
     * 发送 Get 请求。
     * @param	url				请求的地址。大多数浏览器实施了一个同源安全策略，并且要求这个 URL 与包含脚本的文本具有相同的主机名和端口。
     * @param	data			(default = null)发送的数据。
     * @param	method			(default = "get")用于请求的 HTTP 方法。值包括 "get"、"post"、"head"。
     * @param	responseType	(default = "text")Web 服务器的响应类型，可设置为 "text"、"json"、"xml"、"arraybuffer"。
     * @param	headers			(default = null) HTTP 请求的头部信息。参数形如key-value数组：key是头部的名称，不应该包括空白、冒号或换行；value是头部的值，不应该包括换行。比如["Content-Type", "application/json"]。
     * @param   timeout         (default = 10000) 超时时长
     * @param   retryTimes      (default = 0) 请求失败后重试的次数
     * @param   onComplete      (default = null) 请求完成后的响应Handler
     * @param   onProgress      (default = null) 请求过程中的响应Handler
     * @param   onError         (default = null) 请求发生错误时的响应Handler
     */
    public sendsync<T>(url: string, {
                                        data = null, 
                                        method = "get", 
                                        responseType = "text", 
                                        headers = null, 
                                        timeout = 10000, 
                                        retryTimes = 0
                                    }:{
                                        data?: any, 
                                        method?: string, 
                                        responseType?: "text"|"json"|"xml"|"arraybuffer", 
                                        headers?: any[]|null, 
                                        timeout?:number,
                                        retryTimes?:number,
                                        onComplete?: Handler, 
                                        onProgress?: Handler, 
                                        onError?: Handler
                                    }
    ):Promise<T>{
        return new Promise((resolve, reject)=>{
            this.send(url, {data, method, responseType, headers, timeout, retryTimes,
                onComplete:new Handler(this, (result:T)=>{
                    resolve(result);
                }),
                onError:new Handler(this, (message:string)=>{
                    reject(message);
                })
            })
        })
    }

    /**
     * 发送 Get 请求。
     * @param	url				请求的地址。大多数浏览器实施了一个同源安全策略，并且要求这个 URL 与包含脚本的文本具有相同的主机名和端口。
     * @param	data			(default = null)发送的数据。
     * @param	method			(default = "get")用于请求的 HTTP 方法。值包括 "get"、"post"、"head"。
     * @param	responseType	(default = "text")Web 服务器的响应类型，可设置为 "text"、"json"、"xml"、"arraybuffer"。
     * @param	headers			(default = null) HTTP 请求的头部信息。参数形如key-value数组：key是头部的名称，不应该包括空白、冒号或换行；value是头部的值，不应该包括换行。比如["Content-Type", "application/json"]。
     * @param   timeout         (default = 10000) 超时时长
     * @param   retryTimes      (default = 0) 请求失败后重试的次数
     * @param   onComplete      (default = null) 请求完成后的响应Handler
     * @param   onProgress      (default = null) 请求过程中的响应Handler
     * @param   onError         (default = null) 请求发生错误时的响应Handler
     */
    public send(url: string, {
                                data = null, 
                                method = "get", 
                                responseType = "text",
                                headers = null, 
                                timeout = 10000,
                                retryTimes = 0,
                                onComplete=null, 
                                onProgress=null, 
                                onError=null
                        }:{
                            data?: any, 
                            method?: string, 
                            responseType?: "text"|"json"|"xml"|"arraybuffer", 
                            headers?: any[]|null, 
                            timeout?:number,
                            retryTimes?:number,
                            onComplete?: Handler, 
                            onProgress?: Handler, 
                            onError?: Handler
                        }={}):void {
        let sender:HttpRequest = this._pool.allocate();
        sender.timeout = timeout;
        sender.once(HttpRequest.Event.COMPLETE, this, (e)=>{
            this._pool.recover(sender);
            if(onComplete) {
                onComplete.runWith(e);
                onComplete.clear();
            }
        })

        let _onError = (e)=>{
            if(retryTimes-- > 0){
                sender.send(url, data, method, responseType, headers);
                return;
            }
            this._pool.recover(sender);
            if(onError) {
                onError.runWith(e);
                onError.clear();
            }
        }
        
        sender.on(HttpRequest.Event.ERROR, this, _onError);

        sender.on(HttpRequest.Event.TIMEOUT, this, (e)=>{
            _onError(HttpRequest.Event.TIMEOUT);
        });
        
        if(onProgress) {
            sender.on(HttpRequest.Event.PROGRESS, onProgress.caller, onProgress.method, onProgress.args);
            onProgress.clear();
        }
        sender.send(url, data, method, responseType, headers);
    }

    /**
     * 发送 Post 请求。
     * @param	url				请求的地址。大多数浏览器实施了一个同源安全策略，并且要求这个 URL 与包含脚本的文本具有相同的主机名和端口。
     * @param	data			(default = null)发送的数据。
     * @param	responseType	(default = "text")Web 服务器的响应类型，可设置为 "text"、"json"、"xml"、"arraybuffer"。
     * @param	headers			(default = null) HTTP 请求的头部信息。参数形如key-value数组：key是头部的名称，不应该包括空白、冒号或换行；value是头部的值，不应该包括换行。比如["Content-Type", "application/json"]。
     * @param   timeout         (default = 10000) 超时时长
     * @param   retryTimes      (default = 0) 请求失败后重试的次数
     * @param   onComplete      (default = null) 请求完成后的响应Handler
     * @param   onProgress      (default = null) 请求过程中的响应Handler
     * @param   onError         (default = null) 请求发生错误时的响应Handler
     */
    public post(url: string, {data = null, responseType = "text", headers = null, timeout = 10000, retryTimes = 0, onComplete=null, onProgress=null, onError=null}:{
                data?: any, method?: string, responseType?: "text"|"json"|"xml"|"arraybuffer", headers?: any[]|null, 
                timeout?:number,
                retryTimes?:number,
                onComplete?: Handler, onProgress?: Handler, onError?: Handler
            }={}):void {
        this.send(url, {
            method:"post", 
            data, 
            responseType, 
            headers, timeout, retryTimes,
            onComplete, 
            onProgress, 
            onError});
    }

    /**
     * 发送 Get 请求。
     * @param	url				请求的地址。大多数浏览器实施了一个同源安全策略，并且要求这个 URL 与包含脚本的文本具有相同的主机名和端口。
     * @param	data			(default = null)发送的数据。
     * @param	responseType	(default = "text")Web 服务器的响应类型，可设置为 "text"、"json"、"xml"、"arraybuffer"。
     * @param	headers			(default = null) HTTP 请求的头部信息。参数形如key-value数组：key是头部的名称，不应该包括空白、冒号或换行；value是头部的值，不应该包括换行。比如["Content-Type", "application/json"]。
     * @param   onComplete      (default = null) 请求完成后的响应Handler
     * @param   onProgress      (default = null) 请求过程中的响应Handler
     * @param   onError         (default = null) 请求发生错误时的响应Handler
     */
    public get(url: string, {data = null, responseType = "text", headers = null, timeout = 10000, retryTimes = 0, onComplete=null, onProgress=null, onError=null}:{
                    data?: any, method?: string, responseType?: "text"|"json"|"xml"|"arraybuffer", headers?: any[]|null, 
                    timeout?:number,
                    retryTimes?:number,onComplete?: Handler, onProgress?: Handler, onError?: Handler
                }={}):void {
        this.send(url, {
            method:"get", 
            data, 
            responseType, 
            headers, timeout, retryTimes,
            onComplete, 
            onProgress, 
            onError});
    }
}